package com.wg.core.counter;

import cn.hutool.core.date.DateUtil;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 高性能平均值计算器，支持线程安全的统计和计算
 *
 * @author 少爷123
 */
public class AverageCounter {
    private final ReentrantLock lock = new ReentrantLock();
    /**
     * 最大值
     */
    private final AtomicLong maxValue = new AtomicLong(Long.MIN_VALUE);
    /**
     * 最小值
     */
    private final AtomicLong minValue = new AtomicLong(Long.MAX_VALUE);
    /**
     * 累计值
     */
    private final AtomicLong totalValue = new AtomicLong(0);
    /**
     * 平均值
     */
    private final AtomicLong averageValue = new AtomicLong(0);
    /**
     * 累计次数
     */
    private final AtomicLong totalCount = new AtomicLong(0);
    /**
     * 开始时间(秒)
     */
    private volatile long startTime;
    /**
     * 间隔时间(秒)
     */
    private volatile long intervalTime;
    /**
     * 上次检查时间(秒)，用于减少不必要的时间检查
     */
    private volatile long lastCheckTime;

    public AverageCounter() {
        this.startTime = DateUtil.currentSeconds();
        this.lastCheckTime = this.startTime;
    }

    public long getMaxValue() {
        return maxValue.get();
    }

    public long getMinValue() {
        return minValue.get();
    }

    public long getTotalValue() {
        return totalValue.get();
    }

    public long getAverageValue() {
        return averageValue.get();
    }

    public long getTotalCount() {
        return totalCount.get();
    }

    public long getStartTime() {
        return startTime;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
        this.lastCheckTime = startTime;
    }

    public long getIntervalTime() {
        return intervalTime;
    }

    public void setIntervalTime(long intervalTime) {
        this.intervalTime = intervalTime;
    }

    /**
     * 添加一个值到计数器
     *
     * @param value 要添加的值
     */
    public void addValue(long value) {
        // 每秒最多检查一次是否需要计算平均值，减少时间检查开销
        long now = DateUtil.currentSeconds();
        if (now - lastCheckTime >= 1) {
            lastCheckTime = now;
            countAverage();
        }

        // 使用原子操作更新最大值和最小值
        updateMinMax(value);

        // 使用原子操作更新累计值和计数
        totalValue.addAndGet(value);
        totalCount.incrementAndGet();
    }

    /**
     * 更新最大值和最小值
     *
     * @param value 新的值
     */
    private void updateMinMax(long value) {
        long currentMin;
        do {
            currentMin = minValue.get();
            if (value >= currentMin) {
                break;
            }
        } while (!minValue.compareAndSet(currentMin, value));

        long currentMax;
        do {
            currentMax = maxValue.get();
            if (value <= currentMax) {
                break;
            }
        } while (!maxValue.compareAndSet(currentMax, value));
    }

    /**
     * 计算平均值
     */
    private void countAverage() {
        long now = DateUtil.currentSeconds();
        if (now - startTime < intervalTime) {
            return;
        }

        lock.lock();
        try {
            // 再次检查，避免并发问题
            if (now - startTime < intervalTime) {
                return;
            }

            startTime = now;
            long count = totalCount.get();
            long value = totalValue.get();
            long min = minValue.get();
            long max = maxValue.get();

            if (count > 2) {
                // 移除最大值和最小值后计算平均值
                value -= (min + max);
                averageValue.set(value / (count - 2));
            } else if (count > 0) {
                averageValue.set(value / count);
            } else {
                averageValue.set(0);
            }

            // 重置计数器
            totalValue.set(0);
            totalCount.set(0);
            minValue.set(Long.MAX_VALUE);
            maxValue.set(Long.MIN_VALUE);
        } finally {
            lock.unlock();
        }
    }

    /**
     * 手动重置计数器
     */
    public void reset() {
        lock.lock();
        try {
            startTime = DateUtil.currentSeconds();
            lastCheckTime = startTime;
            totalValue.set(0);
            totalCount.set(0);
            minValue.set(Long.MAX_VALUE);
            maxValue.set(Long.MIN_VALUE);
            averageValue.set(0);
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取当前统计周期内的详细统计信息
     *
     * @return 统计信息字符串
     */
    public String getStats() {
        return String.format("计数: %d, 总值: %d, 平均值: %d, 最小值: %d, 最大值: %d",
                totalCount.get(), totalValue.get(), averageValue.get(),
                minValue.get() == Long.MAX_VALUE ? 0 : minValue.get(),
                maxValue.get() == Long.MIN_VALUE ? 0 : maxValue.get());
    }
}
